'  ==========================================================================
'  |                                                                        |
'  | SQLitening Example B                                                   |
'  |                                                                        |
'  ==========================================================================
'  This meaningless program will demo the use of multiple threads.  It will 
'  show you the speed advantage that can be gained with appropate use of 
'  threads.
'  ==========================================================================
'  PUBLIC DOMAIN SOFTWARE
'  The author or authors of this code dedicate any and all
'  copyright interest in this code to the public domain.
'  Anyone is free to copy, modify, publish, use, compile,
'  sell, or distribute the original code, either in source
'  code form or as a compiled binary, for any purpose,
'  commercial or non-commercial, and by any means.
'  Fred Meier - July 2010
'  ==========================================================================

#Compile Exe "..\Bin\ExampleD.Exe"
#Dim All
#Include "..\Inc\SQLitening.Inc"

'============================<[ Declares ]>============================
DECLARE FUNCTION WaitForMultipleObjects LIB "KERNEL32.DLL" ALIAS "WaitForMultipleObjects" (BYVAL nCount AS DWORD, lpHandles AS DWORD, BYVAL bWaitAll AS LONG, BYVAL dwMilliseconds AS DWORD) AS DWORD
DECLARE FUNCTION InterlockedExchangeAdd LIB "KERNEL32.DLL" ALIAS "InterlockedExchangeAdd" (xTarget AS LONG, BYVAL xValue AS LONG) AS LONG

'============================<[ Globals ]>=============================
Global gsServer as String
Global gsPort as String
Global glRecordCount as Long

'=====================<[ Create Database Thread ]>=====================
Function CreateDatabaseThread(byval rlParm as Long) as Long

   Local llDo as Long
   Local llA as Long

   slConnect gsServer, val(gsPort)
   slOpen "ExampleD_" & format$(rlParm) & ".Sld"
   slExe "Begin"
   llA = rlParm * 100 * iif&(gsServer = $Nul, 100, 1)
   for llDo = 1 to llA
      slExe slBuildInsertOrUpdate("T1", "Field 1" & $Nul & "22222")
   next
   slExe "End"
   InterlockedExchangeAdd glRecordCount, llA
   slClose

End Function

'========================<[ Create Database ]>=========================
Function CreateDatabase(byval rlParm as Long) as Long

   Local llDo as Long
   Local llA as Long

   slConnect gsServer, val(gsPort)
   slOpen "ExampleD_" & format$(rlParm) & ".Sld"
   slExe "Begin"
   llA = rlParm * 100 * iif&(gsServer = $Nul, 100, 1)
   for llDo = 1 to llA
      slExe slBuildInsertOrUpdate("T1", "Field 1" & $Nul & "22222")
   next
   slExe "End"
   InterlockedExchangeAdd glRecordCount, llA
   slClose

End Function

'==============================<[ Main ]>==============================
Function PbMain()

   Dim llaHs(1 to 3) as Dword
   Local ldTimer as Double
   Local lsTitle as String

   ' Ask if they want to run local or remote
   select case msgbox("Do you want to run Local or Remote mode?" & $CR & $CR & "Yes = Local             No = Remote", %MB_YESNOCANCEL, "SQLitening Example D")
   case %IDNO
      gsServer = "LocalHost"
      gsServer = inputbox$("Enter remote server name", lsTitle, gsServer)
      if isfalse len(gsServer) then exit function
      gsPort = "51234"
      gsPort = inputbox$("Enter remote port number", lsTitle, gsPort)
      if isfalse len(gsPort) then exit function
      lsTitle = "SQLitening Example D -- Remote Mode (" & gsServer & "  " & gsPort & ")"
      msgbox "Note that the number of inserted records will be much smaller in remote mode due to it being much slower.", , lsTitle

   case %IDYES
      gsServer = $NUL
      lsTitle = "SQLitening Example D -- Local Mode"
   case %IDCANCEL
      exit function
   end select

   ' ==========>>> Create Databases
   slConnect gsServer, val(gsPort)
   slOpen "ExampleD_1.Sld", "C"
   slExe "Drop Table If Exists T1"
   slExe "Create Table T1 (F1, F2)"
   slCopyDatabase "ExampleD_2.Sld"
   slCopyDatabase "ExampleD_3.Sld"

   ' ==========>>> Create Threads
   ' We will create 3 threads.
   ldTimer = timer
   thread create CreateDatabaseThread(1) to  llaHs(1)
   thread create CreateDatabaseThread(2) to  llaHs(2)
   thread create CreateDatabaseThread(3) to  llaHs(3)
   WaitForMultipleObjects(3, byval varptr(llaHs(1)), 1, -1)
   ldTimer = timer - ldTimer
   msgbox "We created 3 databases containing a total of " & format$(glRecordCount, "###,###") & " records using 3 threads in " & format$(ldTimer, "0.00") & " seconds.", , lsTitle

   ' ==========>>> Empty Tables
   slExe "Delete from T1"
   slCopyDatabase "ExampleD_2.Sld"
   slCopyDatabase "ExampleD_3.Sld"
   reset glRecordCount
   slClose

   ' ==========>>> Create Threads
   ldTimer = timer
   CreateDatabase 1
   CreateDatabase 2
   CreateDatabase 3
   ldTimer = timer - ldTimer
   msgbox "We created 3 databases containing a total of " & format$(glRecordCount, "###,###") & " records using no threads in " & format$(ldTimer, "0.00") & " seconds.", , lsTitle

   ' Done
   if gsServer = $NUL then
      if msgbox("End of SQLitening Example D.  Do you want to delete the three databases used in this example?", %MB_YESNO, lsTitle) = %IDYES then
         kill "ExampleD_1.Sld"
         kill "ExampleD_2.Sld"
         kill "ExampleD_3.Sld"
      end if
   else
      msgbox "End of SQLitening Example D.   The following three files were created in the same folder as the service which is running on your server.  You will want to delete them manually." & $CR & $CR & _
             "ExampleD_1.Sld" & $cr & "ExampleD_2.Sld" & $cr & _
             "ExampleD_3.Sld", ,lsTitle
   end if
End Function
